/*
 * @Author: shuai
 * @Date: 2022-12-20 21:24:29
 * @LastEditors: xieyx xieyx@163.com
 * @LastEditTime: 2025-05-15 20:40:19
 * @Description:
 * 1. WINDOW_PROXY_XXX 与 PROXY_TARGET_XXX 成对出现会自动设置代理
 * 2. WINDOW_开头的环境变量会自动生成到全局配置文件中，作为全局变量存在
 */
import { loadEnv, Plugin } from 'vite'
import * as fs from 'fs'
import * as path from 'path'
export default (configName?: string): Plugin => {
  const windowConfigName = configName || 'config'
  return {
    name: 'vite-plugin-autoWindowConfig',
    config(config, env) {
      try {
        const allEnvObj = loadEnv(env.mode, config.root || process.cwd(), '')
        const allEnvKeys = Object.keys(allEnvObj)
        const proxyEnvKeys = allEnvKeys.filter((key) => key.startsWith('WINDOW_PROXY'))
        const serverProxyObj = proxyEnvKeys.reduce((pre, proxyKey) => {
          const proxyTargetKey = proxyKey.replace('WINDOW_PROXY', 'PROXY_TARGET')
          if (!allEnvObj[proxyKey]) return pre
          if (!allEnvKeys.includes(proxyTargetKey)) return pre
          // 组装代理配置对象
          const regExpString = `^${allEnvObj[proxyKey]}`
          pre[regExpString] = {
            target: allEnvObj[proxyTargetKey],
            changeOrigin: true,
            rewrite: (path) => path.replace(new RegExp(regExpString), ''),
          }
          return pre
        }, {})
        // vite 配置文件中代理配置优先级最高
        const finallyProxyObj = { ...serverProxyObj, ...config.server?.proxy }
        // console.log('插件生成代理：', finallyProxyObj)
        // 31: 红, 32: 绿, 33: 黄, 34: 蓝, 35: 紫, 36: 青
        console.log('\x1b[33m 【本地服务器代理关系:】 \x1b[0m')
        Object.entries(finallyProxyObj).forEach(([key, valObj], index) =>
          console.log(index + 1, key, '--->', (valObj as any).target),
        )
        return { server: { proxy: finallyProxyObj } }
      } catch (error) {
        console.log('自动生成代理报错!', error)
        return {}
      }
    },
    configResolved(config) {
      const env = loadEnv(config.env.MODE, config.root, 'WINDOW_')
      const configContent = Object.entries(env)
        .map((cur) => {
          const originVal = cur[1]
          // 工具函数：把字符串转为具体数据类型
          const parseValue = (stringVal) => {
            if ([''].includes(stringVal)) return ''
            try {
              // return eval('(' + stringVal + ')')
              return new Function(`return ${stringVal}`)()
            } catch (error) {
              // console.log(11111111, error)
              return stringVal
            }
          }
          const parseRes = parseValue(originVal)
          // console.log('环境变量值转换后', parseRes, typeof parseRes )
          if (typeof parseRes === 'string') {
            // 这里输出字符串需要把引号也写上
            let quoteType = parseRes.includes("'") ? '\"' : "'"
            return `${cur[0]} = ${quoteType}${parseRes}${quoteType}`
          }
          if (['string', 'number', 'boolean'].includes(typeof parseRes))
            return `${cur[0]} = ${parseRes}`
          // 如果是对象就原样输出，放到js文件后自动变成对象类型
          return `${cur[0]} = ${originVal}`
        })
        .join('\n')
      const configPath = path.join(config.publicDir, `${windowConfigName}.js`)
      fs.createWriteStream(configPath).end(
        configContent +
          '\n' +
          '// 注意：这是读取环境变量文件中以WINDOW_开头的变量自动生成的配置文件，请勿在此添加额外配置信息！',
      )
    },
    transformIndexHtml(html, ctx) {
      return [
        {
          tag: 'script',
          attrs: { src: `./${windowConfigName}.js` },
          children: '',
          injectTo: 'head-prepend',
        },
      ]
    },
  }
}
